package com.one.blocks.security.authc.password;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.util.ContentCachingRequestWrapper;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Optional;

/**
 * @author <a href="mailto:idler41@163.con">linfuxin</a> created on 2023-08-27 10:51:28
 */
public class PasswordAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {

    protected final String FORM_USERNAME_KEY;
    protected final String FORM_PASSWORD_KEY;

    protected final ObjectMapper objectMapper;

    public PasswordAuthenticationProcessingFilter(
            String url, String usernameKey, String passwordKey,
            AuthenticationManager authenticationManager, AuthenticationSuccessHandler successHandler, AuthenticationFailureHandler failureHandler, ObjectMapper objectMapper) {
        super(new AntPathRequestMatcher(url, HttpMethod.POST.name()));
        this.FORM_USERNAME_KEY = usernameKey;
        this.FORM_PASSWORD_KEY = passwordKey;
        this.objectMapper = objectMapper;
        setAuthenticationManager(authenticationManager);
        setAuthenticationSuccessHandler(successHandler);
        setAuthenticationFailureHandler(failureHandler);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        ContentCachingRequestWrapper requestWrapper = (ContentCachingRequestWrapper) request;
        try (BufferedReader reader = requestWrapper.getReader()) {
            //noinspection ResultOfMethodCallIgnored
            reader.read();
        }
        JsonNode form = objectMapper.readTree(requestWrapper.getContentAsByteArray());
        String username = Optional.ofNullable(form.get(FORM_USERNAME_KEY)).map(JsonNode::textValue).orElse(StringUtils.EMPTY);
        String password = Optional.ofNullable(form.get(FORM_PASSWORD_KEY)).map(JsonNode::textValue).orElse(StringUtils.EMPTY);
        return getAuthenticationManager().authenticate(new PasswordAuthenticationToken(username, password));
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        super.doFilter(new ContentCachingRequestWrapper((HttpServletRequest) req), res, chain);
    }

//    private String obtainUsername(HttpServletRequest request) {
//        return request.getParameter(FORM_USERNAME_KEY);
//    }
//
//    private String obtainPassword(HttpServletRequest request) {
//        return request.getParameter(FORM_PASSWORD_KEY);
//    }
}
